home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / quickfix.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-17  |  15.3 KB  |  661 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * quickfix.c: functions for quickfix mode, using a file with error messages
  11.  */
  12.  
  13. #include "vim.h"
  14.  
  15. #ifdef QUICKFIX
  16.  
  17. static void qf_free __ARGS((void));
  18. static char_u *qf_types __ARGS((int, int));
  19.  
  20. /*
  21.  * for each error the next struct is allocated and linked in a list
  22.  */
  23. struct qf_line
  24. {
  25.     struct qf_line  *qf_next;    /* pointer to next error in the list */
  26.     struct qf_line  *qf_prev;    /* pointer to previous error in the list */
  27.     linenr_t         qf_lnum;    /* line number where the error occurred */
  28.     int             qf_fnum;    /* file number for the line */
  29.     int             qf_col;    /* column where the error occurred */
  30.     int             qf_nr;    /* error number */
  31.     char_u        *qf_text;    /* description of the error */
  32.     char_u         qf_cleared;/* set to TRUE if line has been deleted */
  33.     char_u         qf_type;    /* type of the error (mostly 'E') */
  34.     char_u         qf_valid;    /* valid error message detected */
  35. };
  36.  
  37. static struct qf_line *qf_start;    /* pointer to the first error */
  38. static struct qf_line *qf_ptr;        /* pointer to the current error */
  39.  
  40. static int  qf_count = 0;    /* number of errors (0 means no error list) */
  41. static int  qf_index;        /* current index in the error list */
  42. static int  qf_nonevalid;    /* set to TRUE if not a single valid entry found */
  43.  
  44. #define MAX_ADDR    7        /* maximum number of % recognized, also adjust
  45.                     sscanf() below */
  46.  
  47. /*
  48.  * Structure used to hold the info of one part of 'errorformat'
  49.  */
  50. struct eformat
  51. {
  52.     char_u        *fmtstr;        /* pre-formatted part of 'errorformat' */
  53. #ifdef UTS2
  54.     char_u        *(adr[MAX_ADDR]);    /* addresses used */
  55. #else
  56.     void        *(adr[MAX_ADDR]);
  57. #endif
  58.     int            adr_cnt;        /* number of addresses used */
  59.     struct eformat  *next;        /* pointer to next (NULL if last) */
  60. };
  61.  
  62. /*
  63.  * Read the errorfile into memory, line by line, building the error list.
  64.  * Return -1 for error, number of errors for success.
  65.  */
  66.     int
  67. qf_init(efile)
  68.     char_u        *efile;
  69. {
  70.     char_u        *namebuf;
  71.     char_u        *errmsg;
  72.     int            col;
  73.     int            type;
  74.     int            valid;
  75.     long        lnum;
  76.     int            enr;
  77.     FILE        *fd;
  78.     struct qf_line  *qfp = NULL;
  79.     struct qf_line  *qfprev = NULL;    /* init to make SASC shut up */
  80.     char_u        *efmp;
  81.     struct eformat  *fmt_first = NULL;
  82.     struct eformat  *fmt_last = NULL;
  83.     struct eformat  *fmt_ptr;
  84.     char_u        *efm;
  85.     int            maxlen;
  86.     int            len;
  87.     int            i, j;
  88.     int            retval = -1;    /* default: return error flag */
  89.  
  90.     if (efile == NULL)
  91.     return FAIL;
  92.  
  93.     namebuf = alloc(CMDBUFFSIZE + 1);
  94.     errmsg = alloc(CMDBUFFSIZE + 1);
  95.     if (namebuf == NULL || errmsg == NULL)
  96.     goto qf_init_end;
  97.  
  98.     if ((fd = fopen((char *)efile, "r")) == NULL)
  99.     {
  100.     emsg2(e_openerrf, efile);
  101.     goto qf_init_end;
  102.     }
  103.     qf_free();
  104.     qf_index = 0;
  105.  
  106. /*
  107.  * Each part of the format string is copied and modified from p_efm to fmtstr.
  108.  * Only a few % characters are allowed.
  109.  */
  110.     efm = p_efm;
  111.     while (efm[0])
  112.     {
  113.     /*
  114.      * Allocate a new eformat structure and put it at the end of the list
  115.      */
  116.     fmt_ptr = (struct eformat *)alloc((unsigned)sizeof(struct eformat));
  117.     if (fmt_ptr == NULL)
  118.         goto error2;
  119.     if (fmt_first == NULL)        /* first one */
  120.         fmt_first = fmt_ptr;
  121.     else
  122.         fmt_last->next = fmt_ptr;
  123.     fmt_last = fmt_ptr;
  124.     fmt_ptr->next = NULL;
  125.     fmt_ptr->adr_cnt = 0;
  126.  
  127.     /*
  128.      * Isolate one part in the 'errorformat' option
  129.      */
  130.     for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
  131.         if (efm[len] == '\\' && efm[len + 1] != NUL)
  132.         ++len;
  133.  
  134.     /*
  135.      * Get some space to modify the format string into.
  136.      * Must be able to do the largest expansion (x3) MAX_ADDR times.
  137.      */
  138.     maxlen = len + MAX_ADDR * 3 + 4;
  139.     if ((fmt_ptr->fmtstr = alloc(maxlen)) == NULL)
  140.         goto error2;
  141.  
  142.     for (i = 0; i < MAX_ADDR; ++i)
  143.         fmt_ptr->adr[i] = NULL;
  144.  
  145.     for (efmp = efm, i = 0; efmp < efm + len; ++efmp, ++i)
  146.     {
  147.         if (efmp[0] != '%')            /* copy normal character */
  148.         {
  149.         if (efmp[0] == '\\' && efmp + 1 < efm + len)
  150.             ++efmp;
  151.         fmt_ptr->fmtstr[i] = efmp[0];
  152.         }
  153.         else
  154.         {
  155.         fmt_ptr->fmtstr[i++] = '%';
  156.         switch (efmp[1])
  157.         {
  158.         case 'f':    /* file name */
  159.             fmt_ptr->adr[fmt_ptr->adr_cnt++] = namebuf;
  160.             /* FALLTHROUGH */
  161.  
  162.         case 'm':    /* message */
  163.             if (efmp[1] == 'm')
  164.                 fmt_ptr->adr[fmt_ptr->adr_cnt++] = errmsg;
  165.             fmt_ptr->fmtstr[i++] = '[';
  166.             fmt_ptr->fmtstr[i++] = '^';
  167. #ifdef __EMX__
  168.             /* don't allow spaces in file name. This fixes
  169.              * the broken sscanf() where an empty message
  170.              * is accepted as a valid conversion.
  171.              */
  172.             if (efmp[1] == 'f')
  173.                 fmt_ptr->fmtstr[i++] = ' ';
  174. #endif
  175.             if (efmp[2] == '\\')        /* could be "%m\," */
  176.                 j = 3;
  177.             else
  178.                 j = 2;
  179.             if (efmp + j < efm + len)
  180.                 fmt_ptr->fmtstr[i++] = efmp[j];
  181.             else
  182.             {
  183.                 /*
  184.                  * The %f or %m is the last one in the format,
  185.                  * stop at the CR of NL at the end of the line.
  186.                  */
  187. #ifdef USE_CRNL
  188.                 fmt_ptr->fmtstr[i++] = '\r';
  189. #endif
  190.                 fmt_ptr->fmtstr[i++] = '\n';
  191.             }
  192.             fmt_ptr->fmtstr[i] = ']';
  193.             break;
  194.         case 'c':    /* column */
  195.             fmt_ptr->adr[fmt_ptr->adr_cnt++] = &col;
  196.             fmt_ptr->fmtstr[i] = 'd';
  197.             break;
  198.         case 'l':    /* line */
  199.             fmt_ptr->adr[fmt_ptr->adr_cnt++] = &lnum;
  200.             fmt_ptr->fmtstr[i++] = 'l';
  201.             fmt_ptr->fmtstr[i] = 'd';
  202.             break;
  203.         case 'n':    /* error number */
  204.             fmt_ptr->adr[fmt_ptr->adr_cnt++] = &enr;
  205.             fmt_ptr->fmtstr[i] = 'd';
  206.             break;
  207.         case 't':    /* error type */
  208.             fmt_ptr->adr[fmt_ptr->adr_cnt++] = &type;
  209.             fmt_ptr->fmtstr[i] = 'c';
  210.             break;
  211.         case '%':    /* %% */
  212.         case '*':    /* %*: no assignment */
  213.             fmt_ptr->fmtstr[i] = efmp[1];
  214.             break;
  215.         default:
  216.             EMSG("invalid % in format string");
  217.             goto error2;
  218.         }
  219.         if (fmt_ptr->adr_cnt == MAX_ADDR)
  220.         {
  221.             EMSG("too many % in format string");
  222.             goto error2;
  223.         }
  224.         ++efmp;
  225.         }
  226.         if (i >= maxlen - 6)
  227.         {
  228.         EMSG("invalid format string");
  229.         goto error2;
  230.         }
  231.     }
  232.     fmt_ptr->fmtstr[i] = NUL;
  233.  
  234.     /*
  235.      * Advance to next part
  236.      */
  237.     efm = skip_to_option_part(efm + len);    /* skip comma and spaces */
  238.     }
  239.     if (fmt_first == NULL)    /* nothing found */
  240.     {
  241.     EMSG("'errorformat' contains no pattern");
  242.     goto error2;
  243.     }
  244.  
  245.     /*
  246.      * got_int is reset here, because it was probably set when killing the
  247.      * ":make" command, but we still want to read the errorfile then.
  248.      */
  249.     got_int = FALSE;
  250.  
  251.     /*
  252.      * Read the lines in the error file one by one.
  253.      * Try to recognize one of the error formats in each line.
  254.      */
  255.     while (fgets((char *)IObuff, CMDBUFFSIZE, fd) != NULL && !got_int)
  256.     {
  257.     if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line)))
  258.                                       == NULL)
  259.         goto error2;
  260.  
  261.     IObuff[CMDBUFFSIZE] = NUL;  /* for very long lines */
  262.  
  263.     /*
  264.      * Try to match each part of 'errorformat' until we find a complete
  265.      * match or none matches.
  266.      */
  267.     valid = TRUE;
  268.     for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
  269.     {
  270.         namebuf[0] = NUL;
  271.         errmsg[0] = NUL;
  272.         lnum = 0;
  273.         col = 0;
  274.         enr = -1;
  275.         type = 0;
  276.  
  277.         /*
  278.          * If first char of the format and message don't match, there is
  279.          * no need to try sscanf() on it... Somehow I believe there are
  280.          * very slow implementations of sscanf().
  281.          * -- Paul Slootman
  282.          */
  283.         if (fmt_ptr->fmtstr[0] != '%' && fmt_ptr->fmtstr[0] != IObuff[0])
  284.         continue;
  285.  
  286.         if (sscanf((char *)IObuff, (char *)fmt_ptr->fmtstr,
  287.             fmt_ptr->adr[0], fmt_ptr->adr[1], fmt_ptr->adr[2],
  288.             fmt_ptr->adr[3], fmt_ptr->adr[4], fmt_ptr->adr[5],
  289.             fmt_ptr->adr[6]) == fmt_ptr->adr_cnt)
  290.         break;
  291.     }
  292.     if (fmt_ptr == NULL)
  293.     {
  294.         namebuf[0] = NUL;        /* no match found, remove file name */
  295.         lnum = 0;            /* don't jump to this line */
  296.         valid = FALSE;
  297.         STRCPY(errmsg, IObuff);    /* copy whole line to error message */
  298.         if ((efmp = vim_strrchr(errmsg, '\n')) != NULL)
  299.         *efmp = NUL;
  300. #ifdef USE_CRNL
  301.         if ((efmp = vim_strrchr(errmsg, '\r')) != NULL)
  302.         *efmp = NUL;
  303. #endif
  304.     }
  305.  
  306.     if (namebuf[0] == NUL)        /* no file name */
  307.         qfp->qf_fnum = 0;
  308.     else
  309.         qfp->qf_fnum = buflist_add(namebuf);
  310.     if ((qfp->qf_text = vim_strsave(errmsg)) == NULL)
  311.         goto error1;
  312.     if (!vim_isprintc(type))    /* only printable chars allowed */
  313.         type = 0;
  314.     qfp->qf_lnum = lnum;
  315.     qfp->qf_col = col;
  316.     qfp->qf_nr = enr;
  317.     qfp->qf_type = type;
  318.     qfp->qf_valid = valid;
  319.  
  320.     if (qf_count == 0)    /* first element in the list */
  321.     {
  322.         qf_start = qfp;
  323.         qfp->qf_prev = qfp;    /* first element points to itself */
  324.     }
  325.     else
  326.     {
  327.         qfp->qf_prev = qfprev;
  328.         qfprev->qf_next = qfp;
  329.     }
  330.     qfp->qf_next = qfp;    /* last element points to itself */
  331.     qfp->qf_cleared = FALSE;
  332.     qfprev = qfp;
  333.     ++qf_count;
  334.     if (qf_index == 0 && qfp->qf_valid)    /* first valid entry */
  335.     {
  336.         qf_index = qf_count;
  337.         qf_ptr = qfp;
  338.     }
  339.     line_breakcheck();
  340.     }
  341.     if (!ferror(fd))
  342.     {
  343.     if (qf_index == 0)    /* no valid entry found */
  344.     {
  345.         qf_ptr = qf_start;
  346.         qf_index = 1;
  347.         qf_nonevalid = TRUE;
  348.     }
  349.     else
  350.         qf_nonevalid = FALSE;
  351.     retval = qf_count;    /* return number of matches */
  352.     goto qf_init_ok;
  353.     }
  354.     emsg(e_readerrf);
  355. error1:
  356.     vim_free(qfp);
  357. error2:
  358.     qf_free();
  359. qf_init_ok:
  360.     fclose(fd);
  361.     for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
  362.     {
  363.     fmt_first = fmt_ptr->next;
  364.     vim_free(fmt_ptr->fmtstr);
  365.     vim_free(fmt_ptr);
  366.     }
  367. qf_init_end:
  368.     vim_free(namebuf);
  369.     vim_free(errmsg);
  370.     return retval;
  371. }
  372.  
  373. /*
  374.  * jump to a quickfix line
  375.  * if dir == FORWARD go "errornr" valid entries forward
  376.  * if dir == BACKWARD go "errornr" valid entries backward
  377.  * else if "errornr" is zero, redisplay the same line
  378.  * else go to entry "errornr"
  379.  */
  380.     void
  381. qf_jump(dir, errornr, forceit)
  382.     int        dir;
  383.     int        errornr;
  384.     int        forceit;
  385. {
  386.     struct qf_line  *old_qf_ptr;
  387.     int            old_qf_index;
  388.     static char_u   *e_no_more_items = (char_u *)"No more items";
  389.     char_u        *err = e_no_more_items;
  390.     linenr_t        i;
  391.     BUF            *old_curbuf;
  392.  
  393.     if (qf_count == 0)
  394.     {
  395.     emsg(e_quickfix);
  396.     return;
  397.     }
  398.  
  399.     old_qf_ptr = qf_ptr;
  400.     old_qf_index = qf_index;
  401.     if (dir == FORWARD)        /* next valid entry */
  402.     {
  403.     while (errornr--)
  404.     {
  405.         old_qf_ptr = qf_ptr;
  406.         old_qf_index = qf_index;
  407.         do
  408.         {
  409.         if (qf_index == qf_count || qf_ptr->qf_next == NULL)
  410.         {
  411.             qf_ptr = old_qf_ptr;
  412.             qf_index = old_qf_index;
  413.             if (err != NULL)
  414.             {
  415.             emsg(err);
  416.             return;
  417.             }
  418.             errornr = 0;
  419.             break;
  420.         }
  421.         ++qf_index;
  422.         qf_ptr = qf_ptr->qf_next;
  423.         } while (!qf_nonevalid && !qf_ptr->qf_valid);
  424.         err = NULL;
  425.     }
  426.     }
  427.     else if (dir == BACKWARD)        /* previous valid entry */
  428.     {
  429.     while (errornr--)
  430.     {
  431.         old_qf_ptr = qf_ptr;
  432.         old_qf_index = qf_index;
  433.         do
  434.         {
  435.         if (qf_index == 1 || qf_ptr->qf_prev == NULL)
  436.         {
  437.             qf_ptr = old_qf_ptr;
  438.             qf_index = old_qf_index;
  439.             if (err != NULL)
  440.             {
  441.             emsg(err);
  442.             return;
  443.             }
  444.             errornr = 0;
  445.             break;
  446.         }
  447.         --qf_index;
  448.         qf_ptr = qf_ptr->qf_prev;
  449.         } while (!qf_nonevalid && !qf_ptr->qf_valid);
  450.         err = NULL;
  451.     }
  452.     }
  453.     else if (errornr != 0)    /* go to specified number */
  454.     {
  455.     while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL)
  456.     {
  457.         --qf_index;
  458.         qf_ptr = qf_ptr->qf_prev;
  459.     }
  460.     while (errornr > qf_index && qf_index < qf_count && qf_ptr->qf_next != NULL)
  461.     {
  462.         ++qf_index;
  463.         qf_ptr = qf_ptr->qf_next;
  464.     }
  465.     }
  466.  
  467.     /*
  468.      * If there is a file name,
  469.      * read the wanted file if needed, and check autowrite etc.
  470.      */
  471.     old_curbuf = curbuf;
  472.     if (qf_ptr->qf_fnum == 0 || buflist_getfile(qf_ptr->qf_fnum,
  473.                     (linenr_t)1, GETF_SETMARK, forceit) == OK)
  474.     {
  475.     /* When not switched to another buffer, still need to set pc mark */
  476.     if (curbuf == old_curbuf)
  477.         setpcmark();
  478.  
  479.     /*
  480.      * Go to line with error, unless qf_lnum is 0.
  481.      */
  482.     i = qf_ptr->qf_lnum;
  483.     if (i > 0)
  484.     {
  485.         if (i > curbuf->b_ml.ml_line_count)
  486.         i = curbuf->b_ml.ml_line_count;
  487.         curwin->w_cursor.lnum = i;
  488.     }
  489.     if (qf_ptr->qf_col > 0)
  490.     {
  491.         curwin->w_cursor.col = qf_ptr->qf_col - 1;
  492.         adjust_cursor();
  493.     }
  494.     else
  495.         beginline(BL_WHITE | BL_FIX);
  496.     update_topline_redraw();
  497.     smsg((char_u *)"(%d of %d)%s%s: %s", qf_index, qf_count,
  498.           qf_ptr->qf_cleared ? (char_u *)" (line deleted)" : (char_u *)"",
  499.             qf_types(qf_ptr->qf_type, qf_ptr->qf_nr), qf_ptr->qf_text);
  500.     /*
  501.      * if the message is short, redisplay after redrawing the screen
  502.      */
  503.     if (linetabsize(IObuff) < ((int)p_ch - 1) * Columns + sc_col)
  504.     {
  505.         keep_msg = IObuff;
  506.         keep_msg_attr = 0;
  507.     }
  508.     }
  509.     else if (qf_ptr->qf_fnum != 0)
  510.     {
  511.     /*
  512.      * Couldn't open file, so put index back where it was.    This could
  513.      * happen if the file was readonly and we changed something - webb
  514.      */
  515.     qf_ptr = old_qf_ptr;
  516.     qf_index = old_qf_index;
  517.     }
  518. }
  519.  
  520. /*
  521.  * list all errors
  522.  */
  523.     void
  524. qf_list(all)
  525.     int all;        /* If not :cl!, only show recognised errors */
  526. {
  527.     BUF            *buf;
  528.     char_u        *fname;
  529.     struct qf_line  *qfp;
  530.     int            i;
  531.  
  532.     if (qf_count == 0)
  533.     {
  534.     emsg(e_quickfix);
  535.     return;
  536.     }
  537.  
  538.     if (qf_nonevalid)
  539.     all = TRUE;
  540.     qfp = qf_start;
  541.     for (i = 1; !got_int && i <= qf_count; ++i)
  542.     {
  543.     if (qfp->qf_valid || all)
  544.     {
  545.         msg_putchar('\n');
  546.         fname = NULL;
  547.         if (qfp->qf_fnum != 0 &&
  548.                  (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
  549.         fname = buf->b_fname;
  550.         if (fname == NULL)
  551.         sprintf((char *)IObuff, "%2d", i);
  552.         else
  553.         sprintf((char *)IObuff, "%2d %s", i, fname);
  554.         msg_outtrans_attr(IObuff, highlight_attr[HLF_D]);
  555.         if (qfp->qf_lnum == 0)
  556.         IObuff[0] = NUL;
  557.         else if (qfp->qf_col == 0)
  558.         sprintf((char *)IObuff, ":%ld", qfp->qf_lnum);
  559.         else
  560.         sprintf((char *)IObuff, ":%ld, col %d",
  561.                            qfp->qf_lnum, qfp->qf_col);
  562.         sprintf((char *)IObuff + STRLEN(IObuff), "%s: ",
  563.                     qf_types(qfp->qf_type, qfp->qf_nr));
  564.         msg_puts_attr(IObuff, highlight_attr[HLF_N]);
  565.         msg_prt_line(qfp->qf_text);
  566.         out_flush();        /* show one line at a time */
  567.     }
  568.     qfp = qfp->qf_next;
  569.     ui_breakcheck();
  570.     }
  571. }
  572.  
  573. /*
  574.  * free the error list
  575.  */
  576.     static void
  577. qf_free()
  578. {
  579.     struct qf_line *qfp;
  580.  
  581.     while (qf_count)
  582.     {
  583.     qfp = qf_start->qf_next;
  584.     vim_free(qf_start->qf_text);
  585.     vim_free(qf_start);
  586.     qf_start = qfp;
  587.     --qf_count;
  588.     }
  589. }
  590.  
  591. /*
  592.  * qf_mark_adjust: adjust marks
  593.  */
  594.    void
  595. qf_mark_adjust(line1, line2, amount, amount_after)
  596.     linenr_t    line1;
  597.     linenr_t    line2;
  598.     long    amount;
  599.     long    amount_after;
  600. {
  601.     int            i;
  602.     struct qf_line  *qfp;
  603.  
  604.     if (qf_count)
  605.     for (i = 0, qfp = qf_start; i < qf_count; ++i, qfp = qfp->qf_next)
  606.         if (qfp->qf_fnum == curbuf->b_fnum)
  607.         {
  608.         if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
  609.         {
  610.             if (amount == MAXLNUM)
  611.             qfp->qf_cleared = TRUE;
  612.             else
  613.             qfp->qf_lnum += amount;
  614.         }
  615.         if (amount_after && qfp->qf_lnum > line2)
  616.             qfp->qf_lnum += amount_after;
  617.         }
  618. }
  619.  
  620. /*
  621.  * Make a nice message out of the error character and the error number:
  622.  *  char    number    message
  623.  *  e or E    0        "   error"
  624.  *  w or W    0        " warning"
  625.  *  0          0        ""
  626.  *  other     0        " c"
  627.  *  e or E    n        "   error n"
  628.  *  w or W    n        " warning n"
  629.  *  0          n        "   error n"
  630.  *  other     n        " c n"
  631.  */
  632.     static char_u *
  633. qf_types(c, nr)
  634.     int c, nr;
  635. {
  636.     static char_u    buf[20];
  637.     static char_u    cc[3];
  638.     char_u        *p;
  639.  
  640.     if (c == 'W' || c == 'w')
  641.     p = (char_u *)" warning";
  642.     else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
  643.     p = (char_u *)"   error";
  644.     else if (c == 0)
  645.     p = (char_u *)"";
  646.     else
  647.     {
  648.     cc[0] = ' ';
  649.     cc[1] = c;
  650.     cc[2] = NUL;
  651.     p = cc;
  652.     }
  653.  
  654.     if (nr <= 0)
  655.     return p;
  656.  
  657.     sprintf((char *)buf, "%s %3d", p, nr);
  658.     return buf;
  659. }
  660. #endif /* QUICKFIX */
  661.